package ast

var tpl = `{{range .Structs}}{{template "Struct" .}}{{end}}
{{define "Struct"}}
{{UnsetNeedN}}
//////////////////////////////////////////////////////////////////////////////
// [{{.Name}}] begin
var g{{.Name}}Pool = &sync.Pool{}

func Produce{{.Name}}() *{{.Name}} {
	if msg, ok := g{{.Name}}Pool.Get().(*{{.Name}}); ok {
		msg.Reset()
		return msg
	}
	return &{{.Name}}{}
}

func Recycle{{.Name}}(msg *{{.Name}}) {
	g{{.Name}}Pool.Put(msg)
}
{{if .ID}}
const {{.Name}}_ID uint16 = {{.ID}}

func (s *{{.Name}}) ID() uint16 {
	return {{.ID}}
}

func init() {
	myfb.RegisterMessage(
		&{{.Name}}{},
		func() myfb.IMessage {
			return Produce{{.Name}}()
		},
		func(msg myfb.IMessage) {
			Recycle{{.Name}}(msg.(*{{.Name}}))
		})
}
{{end}}

func (s *{{.Name}}) Size() (n int) {
	n = ` + line(`
	{{range .Fields}}
		{{if .IsFixLen}}
			{{template "FixLenSize" .Type}}
		{{end}}
	{{end}}0`) + `
	{{range .Fields}}
		{{if not .IsFixLen}}
			{{template "TypeSize" (TypeInfo .)}}
		{{end}}
	{{end}}
	return
}

func (s *{{.Name}}) Marshal(p []byte) {
	var buf = binary.Buffer{Data: p}
	s.MyfbMarshalWriter(&buf)
}

func (s *{{.Name}}) Unmarshal(p []byte) {
	var buf = binary.Buffer{Data: p}
	s.MyfbUnmarshalReader(&buf)
}

func (s *{{.Name}}) MyfbMarshalWriter(w binary.BinaryWriter) {
	{{range .Fields}}
		{{template "Marshal" (TypeInfo .)}}
	{{end}}
}

func (s *{{.Name}}) MyfbUnmarshalReader(r binary.BinaryReader) {
	{{if IsNeedN}}
		var n int
	{{end}}
	{{range .Fields}}
		{{template "Unmarshal" (TypeInfo .)}}
	{{end}}
}

func (s *{{.Name}}) Reset() {
	{{range .Fields}}
		{{template "Reset" (TypeInfo .)}}
	{{end}}
}
// [{{.Name}}] end
//////////////////////////////////////////////////////////////////////////////
{{end}}
` + line(`

{{define "FixLenSize"}}
	{{if .IsArray}}
		{{.Len}} * {{template "FixLenSize" .Type}}
	{{else}}
		{{.Size}} +
	{{end}}
{{end}}
`) + `
{{define "TypeSize"}}
	{{if .Type.IsArray}}
		{{if not .Type.Len}}
			{{SetNeedN}}
		{{end}}
		{{if .Type.Type.Size}}
			n += 4
			n += len({{.Name}}) * {{.Type.Type.Size}}
		{{else}}
			{{if not .Type.Len}}
				n += 4
			{{end}}
			for {{.I}} := 0; {{.I}}< {{if .Type.Len}}{{.Type.Len}}{{else}}len({{.Name}}){{end}}; {{.I}}++ {
				{{template "TypeSize" (TypeInfo .)}}
			}
		{{end}}
	{{else if .Type.IsPoint}}
		n += 1
		if {{.Name}} != nil {
			{{if .Type.Type.Size}}
				n += {{.Type.Type.Size}}
			{{else}}
				{{template "TypeSize" (TypeInfo .)}}
			{{end}}
		}
	{{else if .Type.IsUnknown}}
		n += {{.Name}}.Size()
	{{else if or (eq .Type.Name "string") (eq .Type.Name "[]byte")}}
		n += {{if not .Type.Len}}2 + {{end}}len({{.Name}})
	{{end}}
{{end}}
{{define "Marshal"}}
	{{if .Type.IsArray}}
		{{if not .Type.Len}}
			w.WriteUint32{{.ByteOrder}}(uint32(len({{.Name}})))
		{{end}}
		for {{.I}} := 0; {{.I}}< {{if .Type.Len}}{{.Type.Len}}{{else}}len({{.Name}}){{end}}; {{.I}}++ {
			{{template "Marshal" (TypeInfo .)}}
		}
	{{else if .Type.IsPoint}}
		if {{.Name}} == nil {
			w.WriteUint8(0);
		} else {
			w.WriteUint8(1);
			{{if .Type.Type.IsUnknown}}
				{{.Name}}.MyfbMarshalWriter(w)
			{{else}}
				{{template "Marshal" (TypeInfo .)}}
			{{end}}
		}
	{{else}}
		{{MarshalFunc .}}
	{{end}}
{{end}}
{{define "Unmarshal"}}
	{{if .Type.IsArray}}
		{{if not .Type.Len}}
			n = int(r.ReadUint32{{.ByteOrder}}())
			{{.Name}} = make({{TypeName .Type}}, n)
		{{end}}
		for {{.I}} := 0; {{.I}}< {{if .Type.Len}}{{.Type.Len}}{{else}}n{{end}}; {{.I}}++ {
			{{template "Unmarshal" (TypeInfo .)}}
		}
	{{else if .Type.IsPoint}}
		if r.ReadUint8() == 1 {
			{{if .Type.Type.IsUnknown}}
				{{.Name}} = new({{TypeName .Type.Type}})
				{{.Name}}.MyfbUnmarshalReader(r)
			{{else}}
				{{template "Unmarshal" (TypeInfo .)}}
			{{end}}
		}
	{{else}}
		{{UnmarshalFunc .}}
	{{end}}
{{end}}
{{define "Reset"}}
	{{if .Type.IsArray}}
		{{if not .Type.Len}}
			{{.Name}} = nil //{{.Name}}[:0]
		{{else}}
			for {{.I}} := 0; {{.I}} < {{.Type.Len}}; {{.I}}++ {
				{{template "Reset" (TypeInfo .)}}
			}
		{{end}}
	{{else if .Type.IsPoint}}
		{{if .Type.Type.IsUnknown}}
			{{ResetFunc .}}
		{{else}}
			{{template "Reset" (TypeInfo .)}}
		{{end}}
	{{else}}
		{{ResetFunc .}}
	{{end}}
{{end}}
`
